﻿#include "widget.h"

#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QNetworkInterface>
#include <QProcess>
#include <QTextStream>
#include <QUuid>
#ifdef Q_OS_WIN
#include <QAxObject>
#include <windows.h>
#endif

Widget::Widget(QWidget *parent) : QWidget(parent)
{
    QString strMachineCode = getMachineCode();
    setCodeToTxt(strMachineCode);
}

Widget::~Widget() { }

QString Widget::getMachineCode()
{
    QString strOrignalCode = "";
#ifdef Q_OS_WIN
    QString strDisc = getWMIHWInfo(DiskDriverSN);
    QString strCpu = getWMIHWInfo(ProcessorID);
    strOrignalCode = strCpu.trimmed() + strDisc.trimmed();
#elif defined(Q_OS_UNIX)
    QString strHostMac = getHostMac();
    QString strDiskSerial = getDiskSerial();
    strOrignalCode = strHostMac.trimmed() + strDiskSerial.trimmed();
#elif defined(Q_OS_MAC)
    SstrMachineCode = getWMIHWInfo(iMacUUID);
#endif
    qWarning() << "getMachineCode " << strOrignalCode;
    return strOrignalCode;
}

void Widget::setCodeToTxt(const QString strMachineCode)
{
    QFile file;
    QString strName =
        QCoreApplication::applicationDirPath() + QDir::separator() + "GMC.txt";
    file.setFileName(strName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
    {
        QTextStream stream(&file);
        stream << strMachineCode;
        file.close();
    }
}

QString Widget::getWMIHWInfo(int HDtype)
{
    QString hwInfo = QStringLiteral("");
#ifdef Q_OS_WIN
    //获取机器码
    // 1.当前原生网卡地址：
    // SELECT MACAddress FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND (NOT
    // (SerialNumber LIKE 'ROOT%'))
    // 2.硬盘序列号
    // SELECT SerialNumber FROM Win32_DiskDrive WHERE(SerialNumber IS NOT NULL) AND
    // (MediaType LIKE 'Fixed hard disk%') 3.获取主板序列号 SELECT SerialNumber FROM
    // Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)
    // 4.处理器ID
    // SELECT ProcessorId  FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)
    // 5.BIOS序列号
    // SELECT SerialNumber  FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)
    // 6.主板型号
    // SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)

    //查询语句列表
    QStringList sqlCmd;
    sqlCmd.clear();
    sqlCmd << QStringLiteral(
        "SELECT MACAddress  FROM Win32_NetworkAdapter WHERE (MACAddress IS NOT NULL) AND "
        "(NOT (SerialNumber LIKE 'ROOT%'))");
    //注意qt调用 wmi时，对查询语句要求很严格，所以 like之类的句子务必精确才能有结果出来
    sqlCmd << QStringLiteral("SELECT SerialNumber  FROM  Win32_DiskDrive WHERE( "
                             "SerialNumber IS NOT NULL) AND (MediaType LIKE 'Fixed%')");
    sqlCmd << QStringLiteral(
        "SELECT SerialNumber FROM Win32_BaseBoard WHERE (SerialNumber IS NOT NULL)");
    sqlCmd << QStringLiteral(
        "SELECT ProcessorId  FROM Win32_Processor WHERE (ProcessorId IS NOT NULL)");
    sqlCmd << QStringLiteral(
        "SELECT SerialNumber  FROM Win32_BIOS WHERE (SerialNumber IS NOT NULL)");
    sqlCmd << QStringLiteral(
        "SELECT Product FROM Win32_BaseBoard WHERE (Product IS NOT NULL)");

    // bios uuid
    sqlCmd << QStringLiteral(
        "SELECT UUID FROM Win32_ComputerSystemProduct WHERE (UUID IS NOT NULL)");

    //结果名称列表
    QStringList columnName;
    columnName.clear();
    columnName << QStringLiteral("MACAddress");
    columnName << QStringLiteral("SerialNumber");
    columnName << QStringLiteral("SerialNumber");
    columnName << QStringLiteral("ProcessorId");
    columnName << QStringLiteral("SerialNumber");
    columnName << QStringLiteral("Product");
    columnName << QStringLiteral("UUID");
    //开始获取
    QAxObject *objIWbemLocator = new QAxObject("WbemScripting.SWbemLocator");
    QAxObject *objWMIService = objIWbemLocator->querySubObject(
        "ConnectServer(QString&,QString&)", QString("."), QString("root\\cimv2"));
    QString strQuery = QStringLiteral("");
    if (HDtype < sqlCmd.size())
        strQuery = sqlCmd.at(HDtype);
    QAxObject *objInterList =
        objWMIService->querySubObject("ExecQuery(QString&))", strQuery);
    QAxObject *enum1 = objInterList->querySubObject("_NewEnum");
    //需要 include windows.h
    IEnumVARIANT *enumInterface = 0;
    QUuid idtt(IID_IEnumVARIANT);
    enum1->queryInterface(idtt, (void **)&enumInterface);
    //初始化 enumInterface
    enumInterface->Reset();
    //循环各个字段
    for (int i = 0; i < objInterList->dynamicCall("Count").toInt(); i++)
    {
        VARIANT *theItem = (VARIANT *)malloc(sizeof(VARIANT));
        if (enumInterface->Next(1, theItem, NULL) != S_FALSE)
        {
            QAxObject *item = new QAxObject((IUnknown *)theItem->punkVal);
            //如果找到值
            if (item)
            {
                if (HDtype < columnName.size())
                {
                    //读取值，并转换为 char*
                    QString strTemp = columnName.at(HDtype);
                    QByteArray ba = strTemp.toLatin1();
                    const char *tempConstChar = ba.data();
                    //                    qDebug()<<"the query is "<<strQuery<<" and cn is
                    //                    "<<tempConstChar;
                    //读取最后的值
                    hwInfo = item->dynamicCall(tempConstChar).toString();
                    //                    ui->textEdit_2->append(tr("\r\n query is %1:,
                    //                    result is %2").arg(strQuery).arg(hwInfo));
                }
            }
            else
            {
                qDebug() << " read system info " << HDtype << " is null";
            }
            delete item;
        }
        else
        {
            qDebug() << " read system info " << HDtype << " is false";
        }
        delete theItem;
    }
    delete objIWbemLocator;
#elif defined(Q_OS_MAC)

    if (iMacUUID != HDtype)
        return hwInfo;
    QProcess proc;
    QStringList args;
#if 0
    args << "-c"
         << "ioreg -rd1 -c IOPlatformExpertDevice |  awk '/IOPlatformSerialNumber/ { print $3; }'";
#endif
    args
        << "-c"
        << "ioreg -rd1 -c IOPlatformExpertDevice |  awk '/IOPlatformUUID/ { print $3; }'";

    proc.start("/bin/bash", args);
    proc.waitForFinished();
    hwInfo = proc.readAll();
    qDebug() << "Ori: " << hwInfo; //可以通过mid(1,11) 取得其中的序列号信息
    hwInfo.remove(QChar('\"'));
    hwInfo.remove(QChar('-'));
    hwInfo.remove(QChar('\n'));
    qDebug() << "Hardware UUID: " << hwInfo;
#endif

    return hwInfo;
}

/**
  功能:获取MAC地址
  返回值:QString类型MAC
**/
QString Widget::getHostMac()
{
    QList<QNetworkInterface> interfaceList = QNetworkInterface::allInterfaces();
    QStringList strMacAddrList;
    for (auto i = 0; i < interfaceList.size(); i++)
    {
        if (interfaceList[i].flags().testFlag(QNetworkInterface::IsUp) &&
            interfaceList[i].flags().testFlag(QNetworkInterface::IsRunning) &&
            interfaceList[i].type() == QNetworkInterface::Ethernet)
        {
            QString strMacAddr = interfaceList[i].hardwareAddress();
            strMacAddr.replace(":", "");
            strMacAddrList.push_back(strMacAddr);
        }
    }
    strMacAddrList.sort();
    QString strMac = nullptr;
    if (!strMacAddrList.isEmpty())
    {
        strMac = strMacAddrList.at(0);
    }

    return strMac;
}

/**
  功能:获取硬盘序列号
  返回值:QString类型硬盘序列号
**/
QString Widget::getDiskSerial()
{
    QString strSerial = nullptr;
    QStringList options;
    //    options << "-c" << "udevadm info --query=property --name=sda | grep
    //    \"ID_SERIAL\"";
    options << "-c"
            << "lsblk -oMOUNTPOINT,PKNAME -P| grep 'MOUNTPOINT=\"/\"' | sed -e "
               "'s/.*\=\"/\\/dev\\//' -e 's/\"//' | xargs lsblk --nodeps -no serial";

    QProcess process;
    process.start("/bin/bash", options);
    process.waitForFinished();
    process.waitForReadyRead();

    QString strAllResult = process.readAllStandardOutput();

    process.close();

    QStringList strResultList = strAllResult.split("\n");
    //    strResultList.sort();
    //    foreach (auto strResult , strResultList) {
    //        int iStart = strResult.indexOf("ID_SERIAL=");
    //        if(-1 == iStart)
    //        {
    //            continue;
    //        }
    //        strSerial = strResult.mid(iStart + QString("ID_SERIAL=").size());
    //        strSerial.replace(" ", "");
    //        break;
    //    }
    if (strResultList.size() >= 1)
    {
        strSerial = strResultList.at(0);
    }

    return strSerial;
}
